#region Imported Namespaces
using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Data;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.Design;
using System.Web.UI.WebControls;

using PHSRAG.Insight21.SearchContext;
using Calendar = PHSRAG.WebControls.Calendar;
using DataAccess = PHSRAG.Utility.DataAccess;
using SessionCachePolicy = PHSRAG.Insight21.Policy.SessionCachePolicy;
using PHSRAG.Insight21.InsightUtilities;
using Policy = PHSRAG.Insight21.Policy;
using UserContext = PHSRAG.Insight21.Context.UserContext;
#endregion

namespace PHSRAG.Insight21.InsightWebControls
{
	/// <summary>
	/// The HumansSearch control is used by Humans summary pages.
	/// </summary>
	[ToolboxData("<{0}:HumansSearch runat=server />"), Designer(typeof(HumansSearchDesigner))] 
	public class HumansSearch : BaseSearch, INamingContainer, ISearch
	{
		#region Constants
		private const string calendarDefaultPrompt = "--Select--";
		#endregion

		#region Instance Variables
		private Policy.ICachePolicy	cachePolicy;
		private TextBox			sponsorName;
		private TextBox			version;
		private Calendar		expirationStartDate;
		private Calendar		expirationEndDate;
		private ControlCollection	controlCollection;
		#endregion

		#region ISearch Members
		/// <summary>
		/// Reset the internal search state. This involves setting the value for all controls 
		/// to their default values and resetting the cached state of the search context.
		/// </summary>		
		public void Reset()
		{
			ResetControls(controlCollection);

			expirationStartDate.Reset();
			expirationEndDate.Reset();
			expirationStartDate.Prompt = calendarDefaultPrompt;
			expirationEndDate.Prompt = calendarDefaultPrompt;
			
			HumansSearchContext searchContext = cachePolicy.GetCachedObject(HumansSearchContext.CacheKey) as HumansSearchContext;
			if (searchContext != null)
				searchContext.Reset(Page.Request.Url.ToString());
		}

		/// <summary>
		/// Get the search criteria from the common search context.
		/// </summary>
		public SearchCriteria SearchCriteria
		{
			get
			{
				return ((HumansSearchContext)cachePolicy.GetCachedObject(HumansSearchContext.CacheKey)).GetSearchCriteria(Page.Request.Url.ToString());
			}
		}


		/// <summary>
		/// Get the search criteria from what's rendered into the search context's search criteria.
		/// This is done by collecting the current values in all controls, 
		/// storing them in the HumansSearchContext, and then returning the search criteria.  We only 
		/// need to update the criterian for non-textbox controls b/c the Common search handles them
		/// </summary>
		public SearchCriteria UpdateSearchCriteria()
		{
			UserContext userContext = (UserContext)cachePolicy.GetCachedObject(UserContext.CacheKey);
			return GetSearchCriteria(userContext.DomainUserId, controlCollection);		
		}

		#endregion
		
		#region Private Properties
		/// <summary>
		/// Determine if the control is in design mode. It is if there is not HTTP context.
		/// </summary>
		private static bool IsDesignMode
		{
			get { return HttpContext.Current == null; }
		}
		#endregion

		#region Internal Methods
		/// <summary>
		/// This method is ONLY invoked by the associated designer to show the control contents at design time.
		/// </summary>
		internal void Design()
		{
			EnsureChildControls();
		}
		#endregion

		#region Overrides

		/// <summary>
		/// Create all controls. Notice that the creation is more than just instantiating the controls. 
		/// It also involves generating the underlying HTML so that the controls shows up per the need.
		/// </summary>
		protected override void CreateChildControls()
		{
			CreateControls();
			GenerateControlTree();
		}

		/// <summary>
		/// Initializes the cachepolicy. Create and cache a HumanSearchContext object if necessary.
		/// Note that controls whose state must persist in the view state MUST be created BEFORE OnInit completes. We do
		/// this simply by invoking EnsureChildControls().
		/// </summary>
		/// <param name="e">Argument associated with the event</param>
		protected override void OnInit(EventArgs e)
		{
			cachePolicy = (Policy.ICachePolicy)Page.Session[Policy.Names.CachePolicyKey];
			HumansSearchContext searchContext = cachePolicy.GetCachedObject(HumansSearchContext.CacheKey) as HumansSearchContext;
			if (searchContext == null)
			{
				searchContext = new HumansSearchContext(cachePolicy);
			}

			EnsureChildControls();
			base.OnInit(e);
			searchContext.GetSearchCriteria(Page.Request.Url.ToString(), controlCollection);
		}

		/// <summary>
		/// Initialize the contents of all controls on first load. If the HumansSearchContext is not cached yet, a
		/// new instance is created and cached.
		/// </summary>
		/// <param name="e">Argument associated with the event</param>
		protected override void OnLoad(EventArgs e)
		{
			cachePolicy = (Policy.ICachePolicy)Page.Session[Policy.Names.CachePolicyKey];

			if (!Page.IsPostBack)
			{
				EnsureChildControls();

				HumansSearchContext searchContext = cachePolicy.GetCachedObject(HumansSearchContext.CacheKey) as HumansSearchContext;
				if (searchContext == null)
				{
                    searchContext = new HumansSearchContext(cachePolicy);
					searchContext.Load(DataAccess.ConnectionString);
					searchContext.Cache();
				}

				SetControlState(searchContext.GetSearchCriteria(Page.Request.Url.ToString(), controlCollection));
			}
		}

        /// <summary>
        /// Set the state for all constituent controls, and register a client script block for the express purpose of
        /// validating the date ranges of all paired Calendar controls in this search block.
        /// </summary>
        /// <param name="e">Argument associated with the event</param>
        /// <remarks>
        /// <protocolId>Why are the actions taken in this method not being done on control load?</protocolId>
        /// <protocolId>During the non-postback construction of the control, the OnLoad method is invoked BEFORE the
        /// CreateChildControls method. The actual creation of constitutent controls are done within the context of
        /// the CreateChildControls methos. Setting the state of control relies on (obviously) the fact that the controls
        /// have been created. So, setting the state in OnLoad for the non-postback condition would fail.</protocolId>
        /// <protocolId>Interestingly, the sequence of method invocations reverses on postback: CreateChildControls is invoked
        /// before OnLoad.</protocolId>
        /// </remarks>
        protected override void OnPreRender(EventArgs e)
        {
            if (!IsDesignMode)
            {
                if (!Page.ClientScript.IsClientScriptBlockRegistered(Constants.ValidateDateRangeScriptKey))
                {
                    string script = string.Format(
                        "<script language=\"javascript\">\n" +
                        "function ValidateDateRange()\n" +
                        "{{\n" +
                        "\tif (document.getElementById(\"{0}\") != null)\n" +
                        "\t\tvar expirationStartText = document.getElementById(\"{0}\").value;\n" +
                        "\tif (document.getElementById(\"{1}\") != null)\n" +
                        "\t\tvar expirationEndText = document.getElementById(\"{1}\").value;\n" +
                        "\tif (expirationStartText != null && expirationStartText != \"\" && expirationEndText != null && expirationEndText != \"\")\n" +
                        "\t{{\n" +
                        "\t\tvar expirationStartDate = new Date(expirationStartText);\n" +
                        "\t\tvar expirationEndDate = new Date(expirationEndText);\n" +
                        "\t\tif (expirationStartDate > expirationEndDate)\n" +
                        "\t\t{{\n" +
                        "\t\t\talert('Expiration Start Date cannot be after Expiration End Date.');\n" +
                        "\t\t\tdocument.getElementById(\"{1}\").focus();\n" +
                        "\t\t\treturn false;\n" +
                        "\t\t}}\n" +
                        "\t\treturn true;\n" +
                        "\t}}\n" +
                        "\treturn true;\n" +
                        "}}\n" +
                        "</script>\n",
                        (expirationStartDate == null) ? "" : expirationStartDate.SelectedDateClientId,
                        (expirationEndDate == null) ? "" : expirationEndDate.SelectedDateClientId);

                    Page.ClientScript.RegisterClientScriptBlock(GetType( ), Constants.ValidateDateRangeScriptKey, script);
                }
            }

            base.OnPreRender (e);
        }

		/// <summary>
		/// Render the control. Note that we simply ensure that all child controls are created, 
		/// and then delegate the call back to the base class.
		/// </summary>
		/// <param name="writer">The writer to use for rendering</param>
		protected override void Render(HtmlTextWriter writer)
		{
			EnsureChildControls();
			base.Render(writer);
		}
		#endregion

		#region Private Methods
		/// <summary>
		/// Create all controls in the CommonSearch.
		/// </summary>
		private void CreateControls()
		{
			Controls.Clear();
			controlCollection = new ControlCollection(this);

            sponsorName = new TextBox();
			sponsorName.ID = "protocolSponsor";
			sponsorName.CssClass = "DataInput";
			sponsorName.Attributes["Label"] = "Sponsor Name";
            controlCollection.Add(sponsorName);			

			version = new TextBox();
			version.ID = "version";
			version.CssClass = "DataInput";
			version.Attributes["Label"] = "Version";
            controlCollection.Add(version);

			expirationStartDate = new Calendar();
			expirationStartDate.ID = "expirationDateFrom";
			expirationStartDate.Attributes["Label"] = "Expiration Date From";
            controlCollection.Add(expirationStartDate);

			expirationEndDate = new Calendar();
			expirationEndDate.ID = "expirationDateTo";
			expirationEndDate.Attributes["Label"] = "Expiration Date To";
            controlCollection.Add(expirationEndDate);
		}

		/// <summary>
		/// Setup the control tree to reflect the actual (and exact) layout of the controls within the ExpandedSearch.
		/// </summary>
		private void GenerateControlTree()
		{
            string searchClientId = ((Policy.ICachePolicy)Page.Session[Policy.Names.CachePolicyKey]).GetCachedObject(Constants.SearchButtonClientIDKey) as string;
            if (searchClientId == null)
                searchClientId = "expandingPanel_commonSearch_search";

			Table t1 = new Table();
			t1.CssClass = "Search";
			t1.CellSpacing = t1.CellPadding = 5;
            t1.Attributes.Add("onkeypress", "return ClickButton(event, '" + searchClientId + "')");
            Controls.Add(t1);

			TableRow t1r1 = new TableRow();
			t1.Rows.Add(t1r1);
			TableCell t1r1c1 = new TableCell();
			t1r1c1.Attributes["valign"] = "top";
			t1r1.Cells.Add(t1r1c1);
			t1r1c1.Controls.Add(GenerateControlTreeForLeftSection());

			TableCell t1r1c3 = new TableCell();
			t1r1c3.Attributes["valign"] = "top";
			t1r1.Cells.Add(t1r1c3);
			t1r1c3.Controls.Add(CreateControlTreeForRightSection());
			
			
		}

		/// <summary>
		/// Setup the control tree to reflect the actual (and exact) layout of the controls within the ExpandedSearch.
		/// This is the left side of the search that contains the two text boxes 
		/// r1c1: Sponsor Name Label
		/// r1c2: Sponsor Name TextBox
		/// r2c1: Version Name/Number Label
		/// r2c2: Version Name/Number TextBox
		/// </summary>
		private Table GenerateControlTreeForLeftSection()
		{	
			Table t = new Table();
			t.CssClass = "Search";
			t.CellSpacing = t.CellPadding = 5;
			TableRow r1 = new TableRow();
			t.Rows.Add(r1);

			TableCell r1c1 = new TableCell();
			r1c1.Attributes["align"] = "right";
			r1c1.Text = "<nobr>&nbsp;Sponsor&nbsp;Name:&nbsp;</nobr>";
			r1.Cells.Add(r1c1);

			TableCell r1c2 = new TableCell();
			r1c2.Attributes["align"] = "left";
			r1.Cells.Add(r1c2);
			r1c2.Controls.Add(sponsorName);			
			
			TableRow r2 = new TableRow();
			t.Rows.Add(r2);
			TableCell r2c1 = new TableCell();
			r2c1.Attributes["align"] = "right";
			r2c1.Text = "<nobr>Version&nbsp;Name/Number:&nbsp;</nobr>";
			r2.Cells.Add(r2c1);

			TableCell r2c2 = new TableCell();
			r2c2.Attributes["align"] = "left";
			r2.Cells.Add(r2c2);
			r2c2.Controls.Add(version);		
			
			
		
			return t;
		}

		/// <summary>
		/// Setup the control tree to reflect the actual (and exact) layout of the controls within the ExpandedSearch.
		/// This is the right side that contains the calendar control 
		/// r1c1: IRB expiration start date label for calendar control
		/// r1c2: IRB expiration start date calendar control 
		/// r1c3: IRB expiration end date label for calendar control 
		/// r1c4: IRB expiration end date calendar control

		/// </summary>
		private Table CreateControlTreeForRightSection()
		{
			Table t = new Table();
			t.CssClass = "Search";
			t.CellSpacing = t.CellPadding = 5;

			TableRow r1 = new TableRow();
			t.Rows.Add(r1);	
			TableCell r1c1 = new TableCell();
			r1c1.Attributes["align"] = "right";
			r1c1.Text = "<nobr>&nbsp;IRB&nbsp;Expiration&nbsp;Date&nbsp;Between:&nbsp;</nobr>";
			r1.Cells.Add(r1c1);

			TableCell r1c2 = new TableCell();
			r1c2.Attributes["align"] = "left";
			r1.Cells.Add(r1c2);
			r1c2.Controls.Add(IsDesignMode ? (Control)new LiteralControl(Calendar.DesignTimeHTML) : (Control)expirationStartDate);
			
			TableCell r1c3 = new TableCell();
			r1c3.Attributes["align"] = "right";
			r1c3.Text = "And:&nbsp;";
			r1.Cells.Add(r1c3);

			TableCell r1c4 = new TableCell();
			r1c4.Attributes["align"] = "left";
			r1.Cells.Add(r1c4);
            r1c4.Controls.Add(IsDesignMode ? (Control)new LiteralControl(Calendar.DesignTimeHTML) : (Control)expirationEndDate);	
		
			return t;
		}
		#endregion
	}

	#region Class HumansSearchDesigner
	/// <summary>
	/// Designer associated with the HumansSearch control.
	/// </summary>
	/// <remarks>
	/// This class cannot be used directly.
	/// </remarks>
	public class HumansSearchDesigner : ControlDesigner
	{
		#region Overrides
		/// <summary>
		/// Force the control to create its child controls for display at design time.
		/// </summary>
		/// <returns>HTML representation of the control</returns>
		public override string GetDesignTimeHtml()
		{
			((HumansSearch)Component).Design();
			return base.GetDesignTimeHtml();
		}
		#endregion
	}

	#endregion
}